package cn.kgc.service.impl;

import cn.kgc.constants.Constants;
import cn.kgc.pojo.*;
import cn.kgc.mapper.MaintainOrderMapper;
import cn.kgc.constants.MaintainStatusEnum;
import cn.kgc.req.AppointmentReq;
import cn.kgc.service.AppointmentService;
import cn.kgc.service.MaintainOrderFlowService;
import cn.kgc.service.MaintainOrderService;
import cn.kgc.service.UsersService;
import cn.kgc.utils.DateUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.ParseException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * 维修订单 服务实现类
 * </p>
 *
 * @author qf
 * @since 2021-08-04
 */
@Service
public class MaintainOrderServiceImpl extends ServiceImpl<MaintainOrderMapper, MaintainOrder> implements MaintainOrderService {

    private final AppointmentService appointmentService;
    private final UsersService usersService;
    private final MaintainOrderFlowService maintainOrderFlowService;

    public MaintainOrderServiceImpl(AppointmentService appointmentService, UsersService usersService, MaintainOrderFlowService maintainOrderFlowService) {
        this.appointmentService = appointmentService;
        this.usersService = usersService;
        this.maintainOrderFlowService = maintainOrderFlowService;
    }

    // 事务，因为保存的时候操作了多个数据库
    // 出现异常的时候进行回滚
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, String> submit(AppointmentReq appointment, Evaluate evaluate)throws ParseException {
        // 只需要返回一个订单号
        Map<String, String> map = new HashMap<>();
        // 1.预约信息表
        Appointment appoint = new Appointment();
        // 给预约信息表赋值
        BeanUtils.copyProperties(appointment, appoint);
        // 给状态赋值 默认为预约
        appoint.setStatus(Constants.Order.AppointStatus.APPOINT);
        appointmentService.save(appoint);
        // 2.订单表
        MaintainOrder maintainOrder = new MaintainOrder();
        String orderNo = this.createOrderNo(); // 获取订单编号
        maintainOrder.setOrderNo(orderNo); // 设置订单编号
        maintainOrder.setUserId(appoint.getUserId()); // 设置用户id
        maintainOrder.setModelId(evaluate.getModelId()); // 设置商品id
        maintainOrder.setEvaluateId(evaluate.getId()); // 设置评估id
        maintainOrder.setPrice(evaluate.getPrice()); // 设置总金额
        maintainOrder.setSubscription(evaluate.getSubscription()); // 设置订单金额
        maintainOrder.setStatus(appoint.getStatus()); // 设置订单状态
        maintainOrder.setCreatedUserId(appoint.getUserId()); // 设置创建用户id
        this.save(maintainOrder); // 保存订单
        // 3.订单流水表
        MaintainOrderFlow maintainOrderFlow = new MaintainOrderFlow();
        maintainOrderFlow.setOrderNo(orderNo); // 设置订单编号
        maintainOrderFlow.setOrderStatus(appoint.getStatus()); // 设置订单状态
        maintainOrderFlow.setOrderStatusDesc(MaintainStatusEnum.APPOINT.getMsg()); // 设置订单状态说明
        // 获取user对象，因为下面的操作人name，只有user表中有
        Users user = usersService.getById(appoint.getUserId());
        maintainOrderFlow.setOperationUId(user.getId()); // 设置操作人id
        maintainOrderFlow.setOperationName(user.getUserName()); // 设置操作人姓名
        maintainOrderFlowService.save(maintainOrderFlow); // 保存订单流水
        map.put("orderNo", orderNo);
        return map;
    }

    private String createOrderNo() throws ParseException {
        // 订单编号：不同的企业不一样，有一点是一样的，不能重复，但是需要有序
        // 正常情况下：当前的时间年月日时分秒纳秒 + 随机数 + 机器id + 预约编号后几位(用户id的相关)
        String orderNo = "";
        // 1.确定一个基础时间
        StringBuffer sb = new StringBuffer(DateUtils.format(new Date(), DateUtils.YYYYMMDDHHMMSSSSS));
        // 2.追加一个时间戳
        sb.append(System.currentTimeMillis());
        orderNo = sb.toString();
        // 3.因为orderNo有可能重复，但是我们不能让它重复
        QueryWrapper<MaintainOrder> wrapper = new QueryWrapper<>();
        wrapper.eq("orderNo", orderNo);
        MaintainOrder order = this.getOne(wrapper);
        // 如果不等于null 说明通过刚刚的订单号查到了数据，说明订单号重复了
        if (order != null) {
            // 递归调用自己重新生成，到不重复为止
            return this.createOrderNo();
        }
        return orderNo;
    }
}
